#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Win11 工具箱
现代化的Windows工具集合，包含右键菜单编辑器等实用工具
"""

import tkinter as tk
from tkinter import ttk, messagebox, filedialog, font
import winreg
import os
import sys
import subprocess
import webbrowser
from typing import List, Dict, Optional
import json
import time
from datetime import datetime
import threading
import ctypes

App_name = 'Win11 工具箱 '+'V1.0.0-25.9.22'


# 管理员权限相关函数
def is_admin():
    """检查是否具有管理员权限"""
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False


def run_as_admin(operation_name="此操作"):
    """请求管理员权限重启程序"""
    if is_admin():
        return True
    
    # 询问用户是否要以管理员身份运行
    result = messagebox.askyesno(
        "需要管理员权限",
        f"{operation_name}需要管理员权限。\n\n"
        "是否以管理员身份重新启动程序？\n\n"
        "注意：当前窗口将关闭。"
    )
    
    if not result:
        return False
    
    try:
        # 以管理员身份重新运行程序
        ctypes.windll.shell32.ShellExecuteW(
            None, 
            "runas", 
            sys.executable, 
            ' '.join([f'"{arg}"' for arg in sys.argv]),
            None, 
            1
        )
        # 退出当前进程
        sys.exit(0)
    except Exception as e:
        messagebox.showerror("错误", f"无法以管理员身份运行：{str(e)}")
        return False

# Win11 风格颜色主题
WIN11_COLORS = {
    'bg': '#f3f3f3',
    'card_bg': '#ffffff',
    'hover_bg': '#e6e6e6',
    'accent': '#0078d4',
    'accent_hover': '#106ebe',
    'text': '#323130',
    'text_secondary': '#605e5c',
    'border': '#e1dfdd',
    'shadow': '#00000010'
}

class ToolItem:
    """工具项类"""
    def __init__(self, name, icon, description, action):
        self.name = name
        self.icon = icon
        self.description = description
        self.action = action

class Win11ToolboxGUI:
    """Win11 风格工具箱主界面"""
    
    def __init__(self):
        print('Win11ToolboxGUI init');
        self.root = tk.Tk()
        self.setup_main_window()
        self.create_tools()
        self.setup_ui()
    
    def setup_main_window(self):
        """设置主窗口"""
        self.root.title(App_name)
        self.root.geometry("1000x700")
        self.root.configure(bg=WIN11_COLORS['bg'])
        self.root.resizable(True, True)
        
        # 设置窗口关闭协议
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        
        # 设置窗口图标（如果有的话）
        try:
            self.root.iconbitmap('icon.ico')
        except:
            pass
    
    def create_tools(self):
        """创建工具列表"""
        self.tools = [
            ToolItem("右键菜单编辑器", "🔧", "管理Windows资源管理器右键菜单", self.open_context_menu_editor),
            ToolItem("截图工具", "�", "强大的屏幕截图和标注工具", self.open_screenshot_tool),
            ToolItem("串口清理工具", "🔌", "扫描和清理占用的COM口", self.open_com_port_cleaner),
            ToolItem("系统信息", "�️", "查看详细的系统信息", self.open_system_info),
            ToolItem("磁盘清理", "�️", "清全理系统垃圾文件", self.open_disk_cleanup),
            ToolItem("注册表编辑", "📝", "安全的注册表编辑工具", self.open_registry_editor),
            ToolItem("网络工具", "🌐", "网络诊断和配置工具", self.open_network_tools),
            ToolItem("启动项管理", "🚀", "管理系统启动项", self.open_startup_manager),
            ToolItem("服务管理", "⚙️", "Windows服务管理", self.open_service_manager),
            ToolItem("文件关联", "�", "管理文件类型关联", self.open_file_association),
            ToolItem("环境变量", "🔗", "编辑系统环境变量", self.open_environment_vars),
            ToolItem("计划任务", "⏰", "管理Windows计划任务", self.open_task_scheduler),
            ToolItem("系统优化", "⚡", "系统性能优化工具", self.open_system_optimizer),
            ToolItem("设置", "⚙️", "工具箱设置和配置", self.open_settings)
        ]
    
    def setup_ui(self):
        """设置用户界面"""
        # 创建主容器
        main_container = tk.Frame(self.root, bg=WIN11_COLORS['bg'])
        main_container.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
        
        # 标题栏
        self.create_title_bar(main_container)
        
        # 搜索栏
        self.create_search_bar(main_container)
        
        # 小工具栏
        self.create_quick_tools_bar(main_container)
        
        # 工具网格
        self.create_tools_grid(main_container)
        
        # 状态栏
        self.create_status_bar(main_container)
    
    def create_title_bar(self, parent):
        """创建标题栏"""
        title_frame = tk.Frame(parent, bg=WIN11_COLORS['bg'], height=60)
        title_frame.pack(fill=tk.X, pady=(0, 20))
        title_frame.pack_propagate(False)
        
        # 主标题
        title_label = tk.Label(
            title_frame, 
            text="Win11 工具箱",
            font=('Segoe UI', 24, 'bold'),
            bg=WIN11_COLORS['bg'],
            fg=WIN11_COLORS['text']
        )
        title_label.pack(side=tk.LEFT, pady=10)
        
        # 副标题
        subtitle_label = tk.Label(
            title_frame,
            text="现代化的Windows系统工具集合",
            font=('Segoe UI', 10),
            bg=WIN11_COLORS['bg'],
            fg=WIN11_COLORS['text_secondary']
        )
        subtitle_label.pack(side=tk.LEFT, padx=(20, 0), pady=15)
    
    def create_search_bar(self, parent):
        """创建搜索栏"""
        search_frame = tk.Frame(parent, bg=WIN11_COLORS['bg'])
        search_frame.pack(fill=tk.X, pady=(0, 20))
        
        # 搜索输入框
        self.search_var = tk.StringVar()
        self.search_var.trace('w', self.on_search_change)
        
        search_entry = tk.Entry(
            search_frame,
            textvariable=self.search_var,
            font=('Segoe UI', 12),
            bg=WIN11_COLORS['card_bg'],
            fg=WIN11_COLORS['text'],
            relief=tk.FLAT,
            bd=1
        )
        search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, ipady=8, ipadx=10)
        
        # 搜索按钮
        search_btn = tk.Button(
            search_frame,
            text="🔍",
            font=('Segoe UI', 12),
            bg=WIN11_COLORS['accent'],
            fg='white',
            relief=tk.FLAT,
            bd=0,
            padx=15
        )
        search_btn.pack(side=tk.RIGHT, padx=(5, 0))
    
    def create_tools_grid(self, parent):
        """创建工具网格"""
        # 创建滚动框架
        canvas = tk.Canvas(parent, bg=WIN11_COLORS['bg'], highlightthickness=0)
        scrollbar = ttk.Scrollbar(parent, orient="vertical", command=canvas.yview)
        self.scrollable_frame = tk.Frame(canvas, bg=WIN11_COLORS['bg'])
        
        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        
        # 绑定鼠标滚轮
        def _on_mousewheel(event):
            canvas.yview_scroll(int(-1*(event.delta/120)), "units")
        canvas.bind_all("<MouseWheel>", _on_mousewheel)
        
        # 创建工具卡片
        self.create_tool_cards()
    
    def create_tool_cards(self):
        """创建工具卡片"""
        # 清空现有卡片
        for widget in self.scrollable_frame.winfo_children():
            widget.destroy()
        
        # 计算网格布局
        cols = 4  # 每行4个工具
        row = 0
        col = 0
        
        for tool in self.tools:
            if self.search_var.get() and self.search_var.get().lower() not in tool.name.lower():
                continue
                
            card = self.create_tool_card(self.scrollable_frame, tool)
            card.grid(row=row, column=col, padx=10, pady=10, sticky="nsew")
            
            col += 1
            if col >= cols:
                col = 0
                row += 1
        
        # 配置网格权重
        for i in range(cols):
            self.scrollable_frame.columnconfigure(i, weight=1)
    
    def create_tool_card(self, parent, tool):
        """创建单个工具卡片"""
        # 主卡片框架
        card = tk.Frame(
            parent,
            bg=WIN11_COLORS['card_bg'],
            relief=tk.FLAT,
            bd=1,
            highlightbackground=WIN11_COLORS['border'],
            highlightthickness=1
        )
        
        # 图标
        icon_label = tk.Label(
            card,
            text=tool.icon,
            font=('Segoe UI Emoji', 32),
            bg=WIN11_COLORS['card_bg'],
            fg=WIN11_COLORS['accent']
        )
        icon_label.pack(pady=(20, 10))
        
        # 工具名称
        name_label = tk.Label(
            card,
            text=tool.name,
            font=('Segoe UI', 12, 'bold'),
            bg=WIN11_COLORS['card_bg'],
            fg=WIN11_COLORS['text']
        )
        name_label.pack(pady=(0, 5))
        
        # 描述
        desc_label = tk.Label(
            card,
            text=tool.description,
            font=('Segoe UI', 9),
            bg=WIN11_COLORS['card_bg'],
            fg=WIN11_COLORS['text_secondary'],
            wraplength=180,
            justify=tk.CENTER
        )
        desc_label.pack(pady=(0, 20), padx=10)
        
        # 绑定点击事件
        def on_click(event, action=tool.action):
            action()
        
        def on_enter(event):
            card.configure(bg=WIN11_COLORS['hover_bg'])
            icon_label.configure(bg=WIN11_COLORS['hover_bg'])
            name_label.configure(bg=WIN11_COLORS['hover_bg'])
            desc_label.configure(bg=WIN11_COLORS['hover_bg'])
        
        def on_leave(event):
            card.configure(bg=WIN11_COLORS['card_bg'])
            icon_label.configure(bg=WIN11_COLORS['card_bg'])
            name_label.configure(bg=WIN11_COLORS['card_bg'])
            desc_label.configure(bg=WIN11_COLORS['card_bg'])
        
        # 绑定事件到所有子组件
        for widget in [card, icon_label, name_label, desc_label]:
            widget.bind("<Button-1>", on_click)
            widget.bind("<Enter>", on_enter)
            widget.bind("<Leave>", on_leave)
        
        # 右键菜单
        context_menu = tk.Menu(self.root, tearoff=0)
        context_menu.add_command(label="打开", command=tool.action)
        context_menu.add_separator()
        context_menu.add_command(label="创建桌面快捷方式", command=lambda: self.create_shortcut(tool))
        context_menu.add_command(label="固定到开始菜单", command=lambda: self.pin_to_start(tool))
        
        def show_context_menu(event):
            context_menu.post(event.x_root, event.y_root)
        
        for widget in [card, icon_label, name_label, desc_label]:
            widget.bind("<Button-3>", show_context_menu)
        
        return card
    
    def create_status_bar(self, parent):
        """创建状态栏"""
        status_frame = tk.Frame(parent, bg=WIN11_COLORS['bg'], height=30)
        status_frame.pack(fill=tk.X, pady=(20, 0))
        status_frame.pack_propagate(False)
        
        self.status_var = tk.StringVar(value="就绪")
        status_label = tk.Label(
            status_frame,
            textvariable=self.status_var,
            font=('Segoe UI', 9),
            bg=WIN11_COLORS['bg'],
            fg=WIN11_COLORS['text_secondary']
        )
        status_label.pack(side=tk.LEFT, pady=5)
        
        # 版本信息
        version_label = tk.Label(
            status_frame,
            text="v1.0.0",
            font=('Segoe UI', 9),
            bg=WIN11_COLORS['bg'],
            fg=WIN11_COLORS['text_secondary']
        )
        version_label.pack(side=tk.RIGHT, pady=5)
    
    def create_quick_tools_bar(self, parent):
        """创建小工具栏"""
        quick_tools_frame = tk.Frame(parent, bg=WIN11_COLORS['card_bg'], relief=tk.FLAT, bd=1,
                                   highlightbackground=WIN11_COLORS['border'], highlightthickness=1)
        quick_tools_frame.pack(fill=tk.X, pady=(0, 20))
        
        # 标题
        title_label = tk.Label(
            quick_tools_frame,
            text="🔧 快速工具",
            font=('Segoe UI', 12, 'bold'),
            bg=WIN11_COLORS['card_bg'],
            fg=WIN11_COLORS['text']
        )
        title_label.pack(side=tk.LEFT, padx=15, pady=10)
        
        # 分隔线
        separator = tk.Frame(quick_tools_frame, width=2, bg=WIN11_COLORS['border'])
        separator.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=5)
        
        # Win11右键菜单修复按钮
        fix_menu_btn = tk.Button(
            quick_tools_frame,
            text="🔄 修复Win11右键菜单",
            font=('Segoe UI', 10),
            bg=WIN11_COLORS['accent'],
            fg='white',
            relief=tk.FLAT,
            bd=0,
            padx=15,
            pady=8,
            command=self.fix_win11_context_menu
        )
        fix_menu_btn.pack(side=tk.LEFT, padx=5, pady=10)
        
        # 添加悬停效果
        def on_enter(event):
            fix_menu_btn.configure(bg=WIN11_COLORS['accent_hover'])
        
        def on_leave(event):
            fix_menu_btn.configure(bg=WIN11_COLORS['accent'])
        
        fix_menu_btn.bind("<Enter>", on_enter)
        fix_menu_btn.bind("<Leave>", on_leave)
        
        # 重启资源管理器按钮
        restart_explorer_btn = tk.Button(
            quick_tools_frame,
            text="🔄 重启资源管理器",
            font=('Segoe UI', 10),
            bg=WIN11_COLORS['hover_bg'],
            fg=WIN11_COLORS['text'],
            relief=tk.FLAT,
            bd=1,
            padx=15,
            pady=8,
            command=self.restart_explorer
        )
        restart_explorer_btn.pack(side=tk.LEFT, padx=5, pady=10)
        
        # 添加悬停效果
        def on_enter_restart(event):
            restart_explorer_btn.configure(bg=WIN11_COLORS['border'])
        
        def on_leave_restart(event):
            restart_explorer_btn.configure(bg=WIN11_COLORS['hover_bg'])
        
        restart_explorer_btn.bind("<Enter>", on_enter_restart)
        restart_explorer_btn.bind("<Leave>", on_leave_restart)
        
        # 清理临时文件按钮
        clean_temp_btn = tk.Button(
            quick_tools_frame,
            text="🗑️ 清理临时文件",
            font=('Segoe UI', 10),
            bg=WIN11_COLORS['hover_bg'],
            fg=WIN11_COLORS['text'],
            relief=tk.FLAT,
            bd=1,
            padx=15,
            pady=8,
            command=self.clean_temp_files
        )
        clean_temp_btn.pack(side=tk.LEFT, padx=5, pady=10)
        
        # 添加悬停效果
        def on_enter_clean(event):
            clean_temp_btn.configure(bg=WIN11_COLORS['border'])
        
        def on_leave_clean(event):
            clean_temp_btn.configure(bg=WIN11_COLORS['hover_bg'])
        
        clean_temp_btn.bind("<Enter>", on_enter_clean)
        clean_temp_btn.bind("<Leave>", on_leave_clean)

    def on_search_change(self, *args):
        """搜索框内容改变时的处理"""
        self.create_tool_cards()
    
    # 工具动作方法
    def open_context_menu_editor(self):
        """打开右键菜单编辑器"""
        self.status_var.set("正在打开右键菜单编辑器...")
        editor = ContextMenuGUI(parent=self.root)
        # 不调用 run()，让它作为子窗口
    
    def open_screenshot_tool(self):
        """打开截图工具"""
        self.status_var.set("正在打开截图工具...")
        screenshot_tool = ScreenshotTool(parent=self.root)
        # 不调用 run()，让它作为子窗口
    
    def open_com_port_cleaner(self):
        """打开串口清理工具"""
        self.status_var.set("正在打开串口清理工具...")
        com_cleaner = ComPortCleanerGUI(parent=self.root)
        # 不调用 run()，让它作为子窗口
    
    def open_system_info(self):
        """打开系统信息"""
        self.status_var.set("正在获取系统信息...")
        try:
            subprocess.run(['msinfo32'], check=True)
        except:
            messagebox.showerror("错误", "无法打开系统信息工具")
    
    def open_disk_cleanup(self):
        """打开磁盘清理"""
        self.status_var.set("正在打开磁盘清理...")
        try:
            subprocess.run(['cleanmgr'], check=True)
        except:
            messagebox.showerror("错误", "无法打开磁盘清理工具")
    
    def open_registry_editor(self):
        """打开注册表编辑器"""
        self.status_var.set("正在打开注册表编辑器...")
        try:
            subprocess.run(['regedit'], check=True)
        except:
            messagebox.showerror("错误", "无法打开注册表编辑器")
    
    def open_network_tools(self):
        """打开网络工具"""
        self.status_var.set("正在打开网络工具...")
        messagebox.showinfo("提示", "网络工具功能正在开发中...")
    
    def open_startup_manager(self):
        """打开启动项管理"""
        self.status_var.set("正在打开任务管理器...")
        try:
            subprocess.run(['taskmgr'], check=True)
        except:
            messagebox.showerror("错误", "无法打开任务管理器")
    
    def open_service_manager(self):
        """打开服务管理"""
        self.status_var.set("正在打开服务管理...")
        try:
            subprocess.run(['services.msc'], check=True)
        except:
            messagebox.showerror("错误", "无法打开服务管理器")
    
    def open_file_association(self):
        """打开文件关联"""
        self.status_var.set("文件关联功能正在开发中...")
        messagebox.showinfo("提示", "文件关联功能正在开发中...")
    
    def open_environment_vars(self):
        """打开环境变量"""
        self.status_var.set("正在打开环境变量...")
        try:
            subprocess.run(['rundll32', 'sysdm.cpl,EditEnvironmentVariables'], check=True)
        except:
            messagebox.showerror("错误", "无法打开环境变量编辑器")
    
    def open_task_scheduler(self):
        """打开计划任务"""
        self.status_var.set("正在打开计划任务...")
        try:
            subprocess.run(['taskschd.msc'], check=True)
        except:
            messagebox.showerror("错误", "无法打开计划任务")
    
    def open_system_optimizer(self):
        """打开系统优化"""
        self.status_var.set("系统优化功能正在开发中...")
        messagebox.showinfo("提示", "系统优化功能正在开发中...")
    
    def open_settings(self):
        """打开设置"""
        self.status_var.set("设置功能正在开发中...")
        messagebox.showinfo("提示", "设置功能正在开发中...")
    
    def create_shortcut(self, tool):
        """创建桌面快捷方式"""
        messagebox.showinfo("提示", f"为 {tool.name} 创建快捷方式功能正在开发中...")
    
    def pin_to_start(self, tool):
        """固定到开始菜单"""
        messagebox.showinfo("提示", f"将 {tool.name} 固定到开始菜单功能正在开发中...")
    
    # 快速工具方法
    def fix_win11_context_menu(self):
        """修复Win11右键菜单，恢复经典右键菜单"""
        self.status_var.set("正在修复Win11右键菜单...")
        
        try:
            # 确认对话框
            result = messagebox.askyesno(
                "确认修复", 
                "此操作将修改注册表以恢复Win10风格的右键菜单。\n\n"
                "修复后需要重启资源管理器才能生效。\n\n"
                "是否继续？"
            )
            
            if not result:
                self.status_var.set("用户取消操作")
                return
            
            # 修改注册表项以禁用Win11新右键菜单
            registry_key = r"SOFTWARE\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32"
            
            try:
                # 创建或打开注册表项
                with winreg.CreateKey(winreg.HKEY_CURRENT_USER, registry_key) as key:
                    # 设置默认值为空字符串，这会禁用Win11的新右键菜单
                    winreg.SetValueEx(key, "", 0, winreg.REG_SZ, "")
                
                self.status_var.set("Win11右键菜单修复成功")
                
                # 询问是否立即重启资源管理器
                restart_result = messagebox.askyesno(
                    "修复成功", 
                    "Win11右键菜单已修复！\n\n"
                    "是否立即重启资源管理器使修复生效？"
                )
                
                if restart_result:
                    self.restart_explorer()
                else:
                    messagebox.showinfo("提示", "修复已完成，请手动重启资源管理器或重启电脑使修复生效。")
                    
            except Exception as e:
                messagebox.showerror("错误", f"修复失败：{str(e)}")
                self.status_var.set("修复失败")
                
        except Exception as e:
            messagebox.showerror("错误", f"操作失败：{str(e)}")
            self.status_var.set("操作失败")
    
    def restart_explorer(self):
        """重启Windows资源管理器"""
        self.status_var.set("正在重启资源管理器...")
        
        try:
            # 确认对话框
            result = messagebox.askyesno(
                "确认重启", 
                "此操作将重启Windows资源管理器。\n\n"
                "所有打开的文件夹窗口将被关闭。\n\n"
                "是否继续？"
            )
            
            if not result:
                self.status_var.set("用户取消操作")
                return
            
            # 结束explorer.exe进程
            subprocess.run(['taskkill', '/f', '/im', 'explorer.exe'], 
                         check=False, capture_output=True)
            
            # 等待一秒
            time.sleep(1)
            
            # 重新启动explorer.exe
            subprocess.Popen(['explorer.exe'])
            
            self.status_var.set("资源管理器重启成功")
            messagebox.showinfo("成功", "资源管理器已重启！")
            
        except Exception as e:
            messagebox.showerror("错误", f"重启失败：{str(e)}")
            self.status_var.set("重启失败")
    
    def clean_temp_files(self):
        """清理系统临时文件"""
        self.status_var.set("正在清理临时文件...")
        
        try:
            # 确认对话框
            result = messagebox.askyesno(
                "确认清理", 
                "此操作将清理以下位置的临时文件：\n\n"
                "• %TEMP% 文件夹\n"
                "• Windows临时文件夹\n"
                "• 回收站（可选）\n\n"
                "是否继续？"
            )
            
            if not result:
                self.status_var.set("用户取消操作")
                return
            
            # 获取临时文件夹路径
            temp_paths = [
                os.environ.get('TEMP', ''),
                os.environ.get('TMP', ''),
                os.path.join(os.environ.get('WINDIR', ''), 'Temp')
            ]
            
            deleted_count = 0
            total_size = 0
            
            for temp_path in temp_paths:
                if temp_path and os.path.exists(temp_path):
                    try:
                        for root, dirs, files in os.walk(temp_path):
                            for file in files:
                                try:
                                    file_path = os.path.join(root, file)
                                    file_size = os.path.getsize(file_path)
                                    os.remove(file_path)
                                    deleted_count += 1
                                    total_size += file_size
                                except:
                                    # 忽略无法删除的文件（可能正在使用）
                                    pass
                    except:
                        # 忽略无法访问的文件夹
                        pass
            
            # 格式化文件大小
            if total_size < 1024:
                size_str = f"{total_size} B"
            elif total_size < 1024 * 1024:
                size_str = f"{total_size / 1024:.1f} KB"
            elif total_size < 1024 * 1024 * 1024:
                size_str = f"{total_size / (1024 * 1024):.1f} MB"
            else:
                size_str = f"{total_size / (1024 * 1024 * 1024):.1f} GB"
            
            self.status_var.set("临时文件清理完成")
            messagebox.showinfo(
                "清理完成", 
                f"临时文件清理完成！\n\n"
                f"删除文件数：{deleted_count}\n"
                f"释放空间：{size_str}"
            )
            
        except Exception as e:
            messagebox.showerror("错误", f"清理失败：{str(e)}")
            self.status_var.set("清理失败")
    
    def on_closing(self):
        """窗口关闭时的处理"""
        print('on_closing')
        # 停止所有正在运行的线程
        for thread in threading.enumerate():
            if thread != threading.main_thread() and thread.is_alive():
                try:
                    # 对于daemon线程，它们会在主线程结束时自动结束
                    if hasattr(thread, '_stop'):
                        thread._stop()
                except:
                    pass
        
        self.root.quit()
        self.root.destroy()
        
        # 强制退出当前线程
        import sys
        sys.exit(0)
    
    def run(self):
        """运行应用"""
        self.root.mainloop()


class ContextMenuManager:
    """Windows右键菜单管理类"""
    
    def __init__(self):
        self.registry_paths = {
            "文件": r"SOFTWARE\Classes\*\shell",
            "文件夹": r"SOFTWARE\Classes\Directory\shell",
            "文件夹背景": r"SOFTWARE\Classes\Directory\Background\shell",
            "桌面背景": r"SOFTWARE\Classes\DesktopBackground\Shell"
        }
    
    def get_menu_items(self, menu_type: str) -> List[Dict]:
        """获取指定类型的右键菜单项"""
        items = []
        registry_path = self.registry_paths.get(menu_type)
        if not registry_path:
            return items
        
        try:
            with winreg.OpenKey(winreg.HKEY_CURRENT_USER, registry_path) as key:
                i = 0
                while True:
                    try:
                        subkey_name = winreg.EnumKey(key, i)
                        item_info = self._get_menu_item_info(registry_path, subkey_name)
                        if item_info:
                            items.append(item_info)
                        i += 1
                    except WindowsError:
                        break
        except FileNotFoundError:
            pass
        
        return items
    
    def _get_menu_item_info(self, base_path: str, key_name: str) -> Optional[Dict]:
        """获取菜单项详细信息"""
        try:
            item_path = f"{base_path}\\{key_name}"
            with winreg.OpenKey(winreg.HKEY_CURRENT_USER, item_path) as key:
                try:
                    display_name = winreg.QueryValueEx(key, "")[0]
                except FileNotFoundError:
                    display_name = key_name
                
                # 获取命令
                command = ""
                try:
                    with winreg.OpenKey(key, "command") as cmd_key:
                        command = winreg.QueryValueEx(cmd_key, "")[0]
                except FileNotFoundError:
                    pass
                
                # 获取图标
                icon = ""
                try:
                    icon = winreg.QueryValueEx(key, "Icon")[0]
                except FileNotFoundError:
                    pass
                
                return {
                    "key_name": key_name,
                    "display_name": display_name,
                    "command": command,
                    "icon": icon,
                    "registry_path": item_path
                }
        except Exception:
            return None
    
    def add_menu_item(self, menu_type: str, key_name: str, display_name: str, 
                     command: str, icon: str = "") -> bool:
        """添加右键菜单项"""
        registry_path = self.registry_paths.get(menu_type)
        if not registry_path:
            return False
        
        try:
            # 创建主键
            item_path = f"{registry_path}\\{key_name}"
            with winreg.CreateKey(winreg.HKEY_CURRENT_USER, item_path) as key:
                if display_name:
                    winreg.SetValueEx(key, "", 0, winreg.REG_SZ, display_name)
                if icon:
                    winreg.SetValueEx(key, "Icon", 0, winreg.REG_SZ, icon)
            
            # 创建command子键
            cmd_path = f"{item_path}\\command"
            with winreg.CreateKey(winreg.HKEY_CURRENT_USER, cmd_path) as cmd_key:
                winreg.SetValueEx(cmd_key, "", 0, winreg.REG_SZ, command)
            
            return True
        except Exception as e:
            print(f"添加菜单项失败: {e}")
            return False
    
    def delete_menu_item(self, menu_type: str, key_name: str) -> bool:
        """删除右键菜单项"""
        registry_path = self.registry_paths.get(menu_type)
        if not registry_path:
            return False
        
        try:
            item_path = f"{registry_path}\\{key_name}"
            # 先删除command子键
            try:
                winreg.DeleteKey(winreg.HKEY_CURRENT_USER, f"{item_path}\\command")
            except FileNotFoundError:
                pass
            
            # 删除主键
            winreg.DeleteKey(winreg.HKEY_CURRENT_USER, item_path)
            return True
        except Exception as e:
            print(f"删除菜单项失败: {e}")
            return False


class ContextMenuGUI:
    """右键菜单管理器GUI界面"""
    
    def __init__(self, parent=None):
        self.manager = ContextMenuManager()
        if parent:
            self.root = tk.Toplevel(parent)
            self.root.transient(parent)
            self.root.grab_set()
        else:
            self.root = tk.Tk()
        self.setup_ui()
        self.current_menu_type = "文件"
        self.refresh_menu_list()
    
    def setup_ui(self):
        """设置用户界面"""
        self.root.title("Windows右键菜单管理器")
        self.root.geometry("800x600")
        self.root.resizable(True, True)
        
        # 设置窗口关闭协议
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        main_frame.rowconfigure(1, weight=1)
        
        # 菜单类型选择
        type_frame = ttk.LabelFrame(main_frame, text="菜单类型", padding="5")
        type_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 10))
        
        self.menu_type_var = tk.StringVar(value="文件")
        menu_types = ["文件", "文件夹", "文件夹背景", "桌面背景"]
        
        for i, menu_type in enumerate(menu_types):
            ttk.Radiobutton(type_frame, text=menu_type, variable=self.menu_type_var,
                           value=menu_type, command=self.on_menu_type_change).grid(
                           row=0, column=i, padx=5, sticky=tk.W)
        
        # 菜单项列表
        list_frame = ttk.LabelFrame(main_frame, text="当前菜单项", padding="5")
        list_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 10))
        list_frame.columnconfigure(0, weight=1)
        list_frame.rowconfigure(0, weight=1)
        
        # 创建Treeview
        columns = ("显示名称", "命令", "图标")
        self.tree = ttk.Treeview(list_frame, columns=columns, show="tree headings", height=10)
        
        # 设置列标题和宽度
        self.tree.heading("#0", text="键名")
        self.tree.column("#0", width=120, minwidth=80)
        
        for col in columns:
            self.tree.heading(col, text=col)
            if col == "命令":
                self.tree.column(col, width=300, minwidth=200)
            else:
                self.tree.column(col, width=120, minwidth=80)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree.yview)
        self.tree.configure(yscrollcommand=scrollbar.set)
        
        self.tree.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
        
        # 绑定右键菜单和键盘事件
        self.tree.bind("<Button-3>", self.show_context_menu)
        self.tree.bind("<Double-1>", self.on_double_click)
        self.tree.bind("<Control-c>", lambda e: self.copy_cell_data("command"))
        self.tree.bind("<Control-Shift-C>", lambda e: self.copy_row_data())
        
        # 创建右键菜单
        self.context_menu = tk.Menu(self.root, tearoff=0)
        self.context_menu.add_command(label="复制键名", command=lambda: self.copy_cell_data("key_name"))
        self.context_menu.add_command(label="复制显示名称", command=lambda: self.copy_cell_data("display_name"))
        self.context_menu.add_command(label="复制命令 (Ctrl+C)", command=lambda: self.copy_cell_data("command"))
        self.context_menu.add_command(label="复制图标路径", command=lambda: self.copy_cell_data("icon"))
        self.context_menu.add_separator()
        self.context_menu.add_command(label="复制整行数据 (Ctrl+Shift+C)", command=self.copy_row_data)
        
        # 按钮框架
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=2, column=0, columnspan=2, pady=(0, 10))
        
        ttk.Button(button_frame, text="添加菜单项", command=self.add_menu_item).pack(side=tk.LEFT, padx=(0, 5))
        ttk.Button(button_frame, text="删除选中项", command=self.delete_selected_item).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="复制命令", command=lambda: self.copy_cell_data("command")).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="刷新列表", command=self.refresh_menu_list).pack(side=tk.LEFT, padx=5)
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN)
        status_bar.grid(row=3, column=0, columnspan=2, sticky=(tk.W, tk.E))
    
    def on_menu_type_change(self):
        """菜单类型改变时的处理"""
        self.current_menu_type = self.menu_type_var.get()
        self.refresh_menu_list()
    
    def refresh_menu_list(self):
        """刷新菜单项列表"""
        # 清空现有项目
        for item in self.tree.get_children():
            self.tree.delete(item)
        
        # 获取并显示菜单项
        items = self.manager.get_menu_items(self.current_menu_type)
        for item in items:
            self.tree.insert("", tk.END, text=item["key_name"],
                           values=(item["display_name"], item["command"], item["icon"]))
        
        self.status_var.set(f"已加载 {len(items)} 个菜单项")
    
    def add_menu_item(self):
        """添加新的菜单项"""
        dialog = AddMenuItemDialog(self.root, self.current_menu_type)
        if dialog.result:
            item_data = dialog.result
            success = self.manager.add_menu_item(
                self.current_menu_type,
                item_data["key_name"],
                item_data["display_name"],
                item_data["command"],
                item_data["icon"]
            )
            
            if success:
                self.refresh_menu_list()
                self.status_var.set("菜单项添加成功")
                messagebox.showinfo("成功", "菜单项已成功添加！")
            else:
                messagebox.showerror("错误", "添加菜单项失败！")
    
    def delete_selected_item(self):
        """删除选中的菜单项"""
        selection = self.tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请先选择要删除的菜单项！")
            return
        
        item = self.tree.item(selection[0])
        key_name = item["text"]
        
        if messagebox.askyesno("确认删除", f"确定要删除菜单项 '{key_name}' 吗？"):
            success = self.manager.delete_menu_item(self.current_menu_type, key_name)
            if success:
                self.refresh_menu_list()
                self.status_var.set("菜单项删除成功")
                messagebox.showinfo("成功", "菜单项已成功删除！")
            else:
                messagebox.showerror("错误", "删除菜单项失败！")
    
    def show_context_menu(self, event):
        """显示右键菜单"""
        # 选中右键点击的项目
        item = self.tree.identify_row(event.y)
        if item:
            self.tree.selection_set(item)
            self.context_menu.post(event.x_root, event.y_root)
    
    def on_double_click(self, event):
        """双击事件处理 - 复制命令"""
        # 检查是否点击在命令列上
        column = self.tree.identify_column(event.x)
        if column == "#2":  # 命令列
            self.copy_cell_data("command")
        else:
            # 如果不是命令列，复制整行数据
            self.copy_row_data()
    
    def copy_cell_data(self, data_type):
        """复制指定类型的单元格数据"""
        selection = self.tree.selection()
        if not selection:
            return
        
        item = self.tree.item(selection[0])
        
        if data_type == "key_name":
            data = item["text"]
        elif data_type == "display_name":
            data = item["values"][0] if item["values"] else ""
        elif data_type == "command":
            data = item["values"][1] if len(item["values"]) > 1 else ""
        elif data_type == "icon":
            data = item["values"][2] if len(item["values"]) > 2 else ""
        else:
            return
        
        # 复制到剪贴板
        self.root.clipboard_clear()
        self.root.clipboard_append(data)
        self.status_var.set(f"已复制: {data_type}")
    
    def copy_row_data(self):
        """复制整行数据"""
        selection = self.tree.selection()
        if not selection:
            return
        
        item = self.tree.item(selection[0])
        key_name = item["text"]
        values = item["values"]
        
        # 格式化整行数据
        row_data = f"键名: {key_name}\n"
        if values:
            row_data += f"显示名称: {values[0]}\n"
            if len(values) > 1:
                row_data += f"命令: {values[1]}\n"
            if len(values) > 2:
                row_data += f"图标: {values[2]}"
        
        # 复制到剪贴板
        self.root.clipboard_clear()
        self.root.clipboard_append(row_data)
        self.status_var.set("已复制整行数据")
    
    def on_closing(self):
        """窗口关闭时的处理"""
        self.root.quit()
        self.root.destroy()
    
    def run(self):
        """运行GUI应用"""
        self.root.mainloop()


class AddMenuItemDialog:
    """添加菜单项对话框"""
    
    def __init__(self, parent, menu_type):
        self.result = None
        self.dialog = tk.Toplevel(parent)
        self.dialog.title("添加菜单项")
        self.dialog.geometry("500x300")
        self.dialog.resizable(False, False)
        self.dialog.transient(parent)
        self.dialog.grab_set()
        
        # 居中显示
        self.dialog.geometry("+%d+%d" % (parent.winfo_rootx() + 50, parent.winfo_rooty() + 50))
        
        self.setup_dialog()
        self.dialog.wait_window()
    
    def setup_dialog(self):
        """设置对话框界面"""
        main_frame = ttk.Frame(self.dialog, padding="20")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 键名
        ttk.Label(main_frame, text="键名 (英文，无空格):").grid(row=0, column=0, sticky=tk.W, pady=(0, 5))
        self.key_name_var = tk.StringVar()
        ttk.Entry(main_frame, textvariable=self.key_name_var, width=50).grid(row=0, column=1, sticky=(tk.W, tk.E), pady=(0, 5))
        
        # 显示名称
        ttk.Label(main_frame, text="显示名称:").grid(row=1, column=0, sticky=tk.W, pady=(0, 5))
        self.display_name_var = tk.StringVar()
        ttk.Entry(main_frame, textvariable=self.display_name_var, width=50).grid(row=1, column=1, sticky=(tk.W, tk.E), pady=(0, 5))
        
        # 命令
        ttk.Label(main_frame, text="执行命令:").grid(row=2, column=0, sticky=tk.W, pady=(0, 5))
        command_frame = ttk.Frame(main_frame)
        command_frame.grid(row=2, column=1, sticky=(tk.W, tk.E), pady=(0, 5))
        command_frame.columnconfigure(0, weight=1)
        
        self.command_var = tk.StringVar()
        command_entry = ttk.Entry(command_frame, textvariable=self.command_var, width=40)
        command_entry.grid(row=0, column=0, sticky=(tk.W, tk.E))
        ttk.Button(command_frame, text="浏览", command=self.browse_command).grid(row=0, column=1, padx=(5, 0))
        
        # 添加命令格式提示 - 放在新的一行
        ttk.Label(main_frame, text="格式示例: \"C:\\Program Files\\app.exe\" \"%1\"", 
                 font=("TkDefaultFont", 8), foreground="gray").grid(row=3, column=1, sticky=tk.W, pady=(0, 10))
        
        # 图标
        ttk.Label(main_frame, text="图标路径 (可选):").grid(row=4, column=0, sticky=tk.W, pady=(0, 5))
        icon_frame = ttk.Frame(main_frame)
        icon_frame.grid(row=4, column=1, sticky=(tk.W, tk.E), pady=(0, 5))
        icon_frame.columnconfigure(0, weight=1)
        
        self.icon_var = tk.StringVar()
        ttk.Entry(icon_frame, textvariable=self.icon_var, width=40).grid(row=0, column=0, sticky=(tk.W, tk.E))
        ttk.Button(icon_frame, text="浏览", command=self.browse_icon).grid(row=0, column=1, padx=(5, 0))
        
        # 按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=5, column=0, columnspan=2, pady=(20, 0))
        
        ttk.Button(button_frame, text="确定", command=self.ok_clicked).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(button_frame, text="取消", command=self.cancel_clicked).pack(side=tk.LEFT)
        
        # 配置网格权重
        main_frame.columnconfigure(1, weight=1)
    
    def browse_command(self):
        """浏览选择命令文件"""
        filename = filedialog.askopenfilename(
            title="选择可执行文件",
            filetypes=[("可执行文件", "*.exe"), ("所有文件", "*.*")]
        )
        if filename:
            # 确保使用正确的Windows路径格式
            # 将正斜杠转换为反斜杠，并确保路径被正确引用
            normalized_path = os.path.normpath(filename)
            self.command_var.set(f'"{normalized_path}" "%1"')
    
    def browse_icon(self):
        """浏览选择图标文件"""
        filename = filedialog.askopenfilename(
            title="选择图标文件",
            filetypes=[("图标文件", "*.ico"), ("可执行文件", "*.exe"), ("所有文件", "*.*")]
        )
        if filename:
            # 确保使用正确的Windows路径格式
            normalized_path = os.path.normpath(filename)
            self.icon_var.set(normalized_path)
    
    def ok_clicked(self):
        """确定按钮点击处理"""
        key_name = self.key_name_var.get().strip()
        display_name = self.display_name_var.get().strip()
        command = self.command_var.get().strip()
        icon = self.icon_var.get().strip()
        
        if not key_name:
            messagebox.showerror("错误", "请输入键名！")
            return
        
        if not display_name:
            messagebox.showerror("错误", "请输入显示名称！")
            return
        
        if not command:
            messagebox.showerror("错误", "请输入执行命令！")
            return
        
        # 验证键名格式
        if not key_name.replace("_", "").replace("-", "").isalnum():
            messagebox.showerror("错误", "键名只能包含字母、数字、下划线和连字符！")
            return
        
        # 验证并规范化路径格式
        try:
            # 如果命令包含引号，提取路径部分进行验证
            if '"' in command:
                # 提取第一个引号对中的路径
                import re
                path_match = re.search(r'"([^"]+)"', command)
                if path_match:
                    exe_path = path_match.group(1)
                    # 验证文件是否存在
                    if not os.path.exists(exe_path):
                        if not messagebox.askyesno("警告", f"文件路径不存在：{exe_path}\n是否继续添加？"):
                            return
        except Exception:
            pass  # 如果验证失败，继续执行
        
        self.result = {
            "key_name": key_name,
            "display_name": display_name,
            "command": command,
            "icon": icon
        }
        
        self.dialog.destroy()
    
    def cancel_clicked(self):
        """取消按钮点击处理"""
        self.dialog.destroy()


class ComPortManager:
    """COM口管理类"""
    
    def __init__(self):
        pass
    
    def get_com_ports(self) -> List[Dict]:
        """获取所有COM口信息，包括已插入和未插入的"""
        com_ports_dict = {}  # 使用字典避免重复
        
        # 获取当前实际插入的设备
        connected_ports = set()
        connected_ports_info = {}
        try:
            import serial.tools.list_ports
            for port in serial.tools.list_ports.comports():
                connected_ports.add(port.device)
                connected_ports_info[port.device] = {
                    "description": port.description,
                    "manufacturer": port.manufacturer or "未知",
                    "hwid": port.hwid
                }
        except ImportError:
            print("警告: pyserial未安装，无法检测已连接设备")
        except Exception as e:
            print(f"获取已连接设备失败: {e}")
        
        # 方法1: 从 SERIALCOMM 读取当前活动的COM口
        try:
            registry_path = r"HARDWARE\DEVICEMAP\SERIALCOMM"
            with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, registry_path) as key:
                i = 0
                while True:
                    try:
                        value_name, value_data, value_type = winreg.EnumValue(key, i)
                        if value_data not in com_ports_dict:
                            com_ports_dict[value_data] = {
                                "device": value_name,
                                "port": value_data,
                                "status": "已插入" if value_data in connected_ports else "活动",
                                "is_connected": value_data in connected_ports
                            }
                        i += 1
                    except WindowsError:
                        break
        except FileNotFoundError:
            pass
        
        # 方法2: 从 COM Name Arbiter 读取所有已分配的COM口（包括未插入的）
        try:
            arbiter_path = r"SYSTEM\CurrentControlSet\Control\COM Name Arbiter"
            with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, arbiter_path) as key:
                try:
                    # ComDB 存储了所有已分配的COM口位图
                    com_db, reg_type = winreg.QueryValueEx(key, "ComDB")
                    if reg_type == winreg.REG_BINARY:
                        # 解析位图，每个位代表一个COM口是否被占用
                        for byte_idx, byte_val in enumerate(com_db):
                            for bit_idx in range(8):
                                if byte_val & (1 << bit_idx):
                                    com_num = byte_idx * 8 + bit_idx + 1
                                    port_name = f"COM{com_num}"
                                    if port_name not in com_ports_dict:
                                        # 这是一个被占用但未活动的COM口
                                        com_ports_dict[port_name] = {
                                            "device": "未知设备",
                                            "port": port_name,
                                            "status": "未插入",
                                            "is_connected": False
                                        }
                except FileNotFoundError:
                    pass
        except Exception as e:
            print(f"读取COM Name Arbiter失败: {e}")
        
        # 方法3: 扫描设备枚举树，查找所有串口设备（包括未插入的）
        try:
            enum_path = r"SYSTEM\CurrentControlSet\Enum"
            self._scan_device_tree(enum_path, com_ports_dict, connected_ports)
        except Exception as e:
            print(f"扫描设备树失败: {e}")
        
        # 转换为列表
        com_ports = list(com_ports_dict.values())
        
        # 获取更详细的设备信息
        for port_info in com_ports:
            # 如果是已连接设备，使用pyserial的信息
            if port_info["is_connected"] and port_info["port"] in connected_ports_info:
                info = connected_ports_info[port_info["port"]]
                port_info["friendly_name"] = info["description"]
                port_info["description"] = info["description"]
                port_info["manufacturer"] = info["manufacturer"]
            else:
                # 否则从注册表获取
                port_info.update(self._get_port_details(port_info["port"], port_info["is_connected"]))
        
        # 按COM口号排序
        com_ports.sort(key=lambda x: self._extract_com_number(x["port"]))
        
        return com_ports
    
    def _extract_com_number(self, port_name: str) -> int:
        """从COM口名称提取数字，用于排序"""
        try:
            import re
            match = re.search(r'COM(\d+)', port_name, re.IGNORECASE)
            if match:
                return int(match.group(1))
        except:
            pass
        return 9999
    
    def _scan_device_tree(self, base_path: str, com_ports_dict: dict, connected_ports: set, depth: int = 0):
        """递归扫描设备树，查找串口设备"""
        if depth > 3:  # 限制递归深度
            return
        
        try:
            with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, base_path) as key:
                i = 0
                while i < 50:  # 限制每层扫描数量
                    try:
                        subkey_name = winreg.EnumKey(key, i)
                        subkey_path = f"{base_path}\\{subkey_name}"
                        
                        # 检查是否是串口设备
                        try:
                            with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, subkey_path) as subkey:
                                # 查找 FriendlyName 中包含 COM 的设备
                                try:
                                    friendly_name = winreg.QueryValueEx(subkey, "FriendlyName")[0]
                                    import re
                                    match = re.search(r'\(COM(\d+)\)', friendly_name)
                                    if match:
                                        port_name = f"COM{match.group(1)}"
                                        if port_name not in com_ports_dict:
                                            # 检查设备状态
                                            is_connected = port_name in connected_ports
                                            com_ports_dict[port_name] = {
                                                "device": subkey_name,
                                                "port": port_name,
                                                "status": "已插入" if is_connected else "未插入",
                                                "is_connected": is_connected,
                                                "friendly_name": friendly_name
                                            }
                                except FileNotFoundError:
                                    pass
                        except:
                            pass
                        
                        # 递归搜索子键
                        if depth < 2:  # 只在前两层递归
                            self._scan_device_tree(subkey_path, com_ports_dict, connected_ports, depth + 1)
                        
                        i += 1
                    except WindowsError:
                        break
        except:
            pass
    
    def _get_port_details(self, port_name: str, is_connected: bool) -> Dict:
        """获取COM口详细信息"""
        details = {
            "description": "未知设备",
            "manufacturer": "未知",
            "friendly_name": port_name
        }
        
        # 如果设备已连接，尝试从pyserial获取详细信息
        if is_connected:
            try:
                import serial.tools.list_ports
                for port in serial.tools.list_ports.comports():
                    if port.device == port_name:
                        details["friendly_name"] = port.description or port_name
                        details["description"] = port.description or "未知设备"
                        details["manufacturer"] = port.manufacturer or "未知"
                        return details
            except ImportError:
                pass
            except Exception as e:
                print(f"获取端口详情失败: {e}")
        
        # 如果设备未连接或无法从pyserial获取，从注册表搜索
        try:
            # 搜索设备注册表
            base_path = r"SYSTEM\CurrentControlSet\Enum"
            
            def search_device(key_path, depth=0):
                # 限制递归深度，避免搜索太久
                if depth > 4:
                    return False
                    
                try:
                    with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path) as key:
                        try:
                            friendly_name = winreg.QueryValueEx(key, "FriendlyName")[0]
                            if port_name in friendly_name:
                                details["friendly_name"] = friendly_name
                                try:
                                    desc = winreg.QueryValueEx(key, "DeviceDesc")[0]
                                    # 移除可能的前缀 (如 "@oem1.inf,%device%;")
                                    if ';' in desc:
                                        desc = desc.split(';')[-1]
                                    details["description"] = desc
                                except:
                                    pass
                                try:
                                    mfg = winreg.QueryValueEx(key, "Mfg")[0]
                                    # 移除可能的前缀
                                    if ';' in mfg:
                                        mfg = mfg.split(';')[-1]
                                    details["manufacturer"] = mfg
                                except:
                                    pass
                                return True
                        except:
                            pass
                        
                        # 递归搜索子键
                        i = 0
                        while True:
                            try:
                                subkey_name = winreg.EnumKey(key, i)
                                if search_device(f"{key_path}\\{subkey_name}", depth + 1):
                                    return True
                                i += 1
                            except WindowsError:
                                break
                except:
                    pass
                return False
            
            search_device(base_path)
        except:
            pass
        
        # 如果未连接且没找到详细信息，标记为未插入设备
        if not is_connected and details["description"] == "未知设备":
            details["description"] = "设备未插入（仅占用端口号）"
        
        return details
    
    def delete_com_port(self, port_name: str) -> bool:
        """删除COM口注册表项"""
        success_serialcomm = False
        success_comdb = False
        
        # 提取COM口号
        import re
        match = re.search(r'COM(\d+)', port_name, re.IGNORECASE)
        if not match:
            print(f"无效的COM口名称: {port_name}")
            return False
        
        com_number = int(match.group(1))
        print(f"\n开始清理 {port_name}...")
        
        # 步骤1: 从SERIALCOMM中删除（如果存在）
        try:
            registry_path = r"HARDWARE\DEVICEMAP\SERIALCOMM"
            with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, registry_path, 0, 
                              winreg.KEY_ALL_ACCESS) as key:
                i = 0
                while True:
                    try:
                        value_name, value_data, value_type = winreg.EnumValue(key, i)
                        if value_data == port_name:
                            winreg.DeleteValue(key, value_name)
                            print(f"  ✓ 从SERIALCOMM删除")
                            success_serialcomm = True
                            break
                        i += 1
                    except WindowsError:
                        break
        except Exception as e:
            print(f"  ✗ 从SERIALCOMM删除失败: {e}")
        
        # 步骤2: 从COM Name Arbiter的ComDB位图中释放COM口号（这是关键步骤）
        try:
            arbiter_path = r"SYSTEM\CurrentControlSet\Control\COM Name Arbiter"
            with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, arbiter_path, 0,
                              winreg.KEY_READ | winreg.KEY_WRITE) as key:
                try:
                    com_db, reg_type = winreg.QueryValueEx(key, "ComDB")
                    if reg_type == winreg.REG_BINARY:
                        # 将字节数组转换为可修改的列表
                        com_db_list = list(com_db)
                        
                        # 计算要清除的位
                        byte_idx = (com_number - 1) // 8
                        bit_idx = (com_number - 1) % 8
                        
                        if byte_idx < len(com_db_list):
                            # 检查该位是否已被占用
                            byte_value = com_db_list[byte_idx]
                            is_occupied = (byte_value & (1 << bit_idx)) != 0
                            
                            if is_occupied:
                                # 清除对应的位（设置为0）
                                com_db_list[byte_idx] &= ~(1 << bit_idx)
                                
                                # 写回注册表
                                new_com_db = bytes(com_db_list)
                                winreg.SetValueEx(key, "ComDB", 0, winreg.REG_BINARY, new_com_db)
                                print(f"  ✓ 从ComDB释放端口号")
                                success_comdb = True
                            # else: COM口在ComDB中未被占用，跳过
                        # else: COM口超出ComDB范围
                except FileNotFoundError:
                    print("✗ ComDB不存在")
        except PermissionError:
            print(f"✗ 权限不足，无法修改ComDB（需要管理员权限）")
            return False
        except Exception as e:
            print(f"✗ 从ComDB删除失败: {e}")
            import traceback
            traceback.print_exc()
        
        # 步骤3: 从设备枚举树中处理设备（对于未插入的设备，这是关键步骤）
        success_device_tree = False
        try:
            if self._delete_device_from_enum(port_name):
                success_device_tree = True
        except Exception as e:
            print(f"  ✗ 处理设备失败: {e}")
        
        # 步骤4: 使用 pnputil 卸载驱动（如果可能）
        success_pnputil = False
        try:
            success_pnputil = self._uninstall_device_with_pnputil(port_name)
        except Exception as e:
            print(f"  ✗ pnputil卸载失败: {e}")
        
        # 判断清理是否成功
        # 只要有任何一个步骤成功就算成功
        if success_device_tree or success_comdb or success_serialcomm or success_pnputil:
            print(f"✓ {port_name} 清理完成")
            if success_device_tree:
                print(f"  提示: 设备已标记为禁用，重启后生效")
            return True
        else:
            print(f"✗ {port_name} 清理失败（未在任何位置找到）")
            return False
    
    def _uninstall_device_with_pnputil(self, port_name: str) -> bool:
        """使用 pnputil 卸载设备"""
        try:
            # 使用 pnputil /enum-devices 查找设备
            result = subprocess.run(
                ['pnputil', '/enum-devices', '/class', 'Ports'],
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode == 0:
                # 解析输出，查找包含目标COM口的设备实例ID
                lines = result.stdout.split('\n')
                instance_id = None
                
                for i, line in enumerate(lines):
                    if port_name in line or f'({port_name})' in line:
                        # 向上查找实例ID
                        for j in range(max(0, i-10), i):
                            if 'Instance ID:' in lines[j] or '实例 ID:' in lines[j]:
                                instance_id = lines[j].split(':', 1)[1].strip()
                                break
                        if instance_id:
                            break
                
                if instance_id:
                    print(f"  找到设备实例: {instance_id}")
                    # 尝试删除设备
                    result = subprocess.run(
                        ['pnputil', '/remove-device', instance_id],
                        capture_output=True,
                        text=True,
                        timeout=10
                    )
                    
                    if result.returncode == 0:
                        print(f"  ✓ 使用pnputil成功卸载设备")
                        return True
                    else:
                        print(f"  ✗ pnputil卸载失败: {result.stderr}")
        except subprocess.TimeoutExpired:
            print(f"  ✗ pnputil命令超时")
        except FileNotFoundError:
            # pnputil 不可用（旧版Windows）
            pass
        except Exception as e:
            print(f"  ✗ pnputil执行失败: {e}")
        
        return False
    
    def _delete_device_from_enum(self, port_name: str) -> bool:
        """从设备枚举树中删除设备（通过标记为需要重新枚举）"""
        success = False
        try:
            base_path = r"SYSTEM\CurrentControlSet\Enum"
            
            def search_and_mark_delete(key_path, depth=0):
                nonlocal success
                if depth > 4 or success:
                    return
                    
                try:
                    with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path, 0, 
                                      winreg.KEY_READ) as key:
                        # 查找包含目标COM口的设备
                        try:
                            friendly_name = winreg.QueryValueEx(key, "FriendlyName")[0]
                            import re
                            match = re.search(r'\(COM(\d+)\)', friendly_name)
                            if match and f"COM{match.group(1)}" == port_name:
                                # 找到了目标设备
                                print(f"找到设备: {friendly_name}")
                                print(f"设备路径: {key_path}")
                                
                                # 方法1: 尝试禁用设备（通过修改ConfigFlags）
                                try:
                                    with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path, 0,
                                                      winreg.KEY_SET_VALUE) as write_key:
                                        # ConfigFlags: 0x00000001 = CONFIGFLAG_DISABLED
                                        # 添加 0x00000002 = CONFIGFLAG_REMOVED
                                        winreg.SetValueEx(write_key, "ConfigFlags", 0, 
                                                        winreg.REG_DWORD, 0x00000003)
                                        print(f"✓ 已标记设备为禁用和删除状态")
                                        success = True
                                except Exception as e:
                                    print(f"标记设备失败: {e}")
                                
                                # 方法2: 删除 PortName 值（如果存在）
                                try:
                                    device_params_path = f"{key_path}\\Device Parameters"
                                    with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 
                                                      device_params_path, 0,
                                                      winreg.KEY_SET_VALUE) as params_key:
                                        try:
                                            winreg.DeleteValue(params_key, "PortName")
                                            print(f"✓ 已删除设备的PortName映射")
                                            success = True
                                        except FileNotFoundError:
                                            pass
                                except Exception as e:
                                    print(f"删除PortName失败: {e}")
                                
                                return
                        except FileNotFoundError:
                            pass
                        
                        # 递归搜索子键
                        if depth < 3:
                            i = 0
                            while i < 100:
                                try:
                                    subkey_name = winreg.EnumKey(key, i)
                                    search_and_mark_delete(f"{key_path}\\{subkey_name}", depth + 1)
                                    if success:
                                        return
                                    i += 1
                                except WindowsError:
                                    break
                except:
                    pass
            
            search_and_mark_delete(base_path)
        except Exception as e:
            print(f"处理设备失败: {e}")
        
        return success
    
    def delete_all_com_ports(self) -> int:
        """删除所有COM口，返回删除数量"""
        deleted_count = 0
        ports = self.get_com_ports()
        
        for port in ports:
            if self.delete_com_port(port["port"]):
                deleted_count += 1
        
        return deleted_count


class ComPortCleanerGUI:
    """COM口清理工具GUI界面"""
    
    def __init__(self, parent=None):
        self.manager = ComPortManager()
        if parent:
            self.root = tk.Toplevel(parent)
            self.root.transient(parent)
            self.root.grab_set()
        else:
            self.root = tk.Tk()
        self.setup_ui()
        self.refresh_port_list()
    
    def setup_ui(self):
        """设置用户界面"""
        self.root.title("COM口清理工具")
        self.root.geometry("900x600")
        self.root.resizable(True, True)
        self.root.configure(bg=WIN11_COLORS['bg'])
        
        # 设置窗口关闭协议
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        
        # 创建主框架
        main_frame = tk.Frame(self.root, bg=WIN11_COLORS['bg'], padx=20, pady=20)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 标题
        title_frame = tk.Frame(main_frame, bg=WIN11_COLORS['bg'])
        title_frame.pack(fill=tk.X, pady=(0, 20))
        
        title_label = tk.Label(
            title_frame,
            text="🔌 COM口清理工具",
            font=('Segoe UI', 20, 'bold'),
            bg=WIN11_COLORS['bg'],
            fg=WIN11_COLORS['text']
        )
        title_label.pack(side=tk.LEFT)
        
        subtitle_label = tk.Label(
            title_frame,
            text="扫描和清理占用的串口",
            font=('Segoe UI', 10),
            bg=WIN11_COLORS['bg'],
            fg=WIN11_COLORS['text_secondary']
        )
        subtitle_label.pack(side=tk.LEFT, padx=(15, 0))
        
        # 管理员权限状态
        admin_status = "🛡️ 管理员模式" if is_admin() else "⚠️ 普通模式（清理需要管理员权限）"
        admin_color = '#107c10' if is_admin() else '#d83b01'
        
        admin_label = tk.Label(
            title_frame,
            text=admin_status,
            font=('Segoe UI', 9, 'bold'),
            bg=WIN11_COLORS['bg'],
            fg=admin_color
        )
        admin_label.pack(side=tk.RIGHT, padx=(15, 0))
        
        # 工具栏
        toolbar_frame = tk.Frame(main_frame, bg=WIN11_COLORS['card_bg'], 
                                relief=tk.FLAT, bd=1,
                                highlightbackground=WIN11_COLORS['border'], 
                                highlightthickness=1)
        toolbar_frame.pack(fill=tk.X, pady=(0, 15))
        
        # 刷新按钮
        refresh_btn = tk.Button(
            toolbar_frame,
            text="🔄 刷新列表",
            font=('Segoe UI', 10),
            bg=WIN11_COLORS['accent'],
            fg='white',
            relief=tk.FLAT,
            bd=0,
            padx=15,
            pady=8,
            command=self.refresh_port_list
        )
        refresh_btn.pack(side=tk.LEFT, padx=10, pady=10)
        
        # 全选按钮
        select_all_btn = tk.Button(
            toolbar_frame,
            text="☑️ 全选",
            font=('Segoe UI', 10),
            bg=WIN11_COLORS['hover_bg'],
            fg=WIN11_COLORS['text'],
            relief=tk.FLAT,
            bd=1,
            padx=15,
            pady=8,
            command=self.select_all
        )
        select_all_btn.pack(side=tk.LEFT, padx=5, pady=10)
        
        # 取消全选按钮
        deselect_all_btn = tk.Button(
            toolbar_frame,
            text="☐ 取消全选",
            font=('Segoe UI', 10),
            bg=WIN11_COLORS['hover_bg'],
            fg=WIN11_COLORS['text'],
            relief=tk.FLAT,
            bd=1,
            padx=15,
            pady=8,
            command=self.deselect_all
        )
        deselect_all_btn.pack(side=tk.LEFT, padx=5, pady=10)
        
        # 分隔线
        separator = tk.Frame(toolbar_frame, width=2, bg=WIN11_COLORS['border'])
        separator.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=5)
        
        # 清理选中按钮
        clean_selected_btn = tk.Button(
            toolbar_frame,
            text="🗑️ 清理选中",
            font=('Segoe UI', 10),
            bg='#d83b01',
            fg='white',
            relief=tk.FLAT,
            bd=0,
            padx=15,
            pady=8,
            command=self.clean_selected
        )
        clean_selected_btn.pack(side=tk.LEFT, padx=5, pady=10)
        
        # 清理全部按钮
        clean_all_btn = tk.Button(
            toolbar_frame,
            text="🗑️ 清理全部",
            font=('Segoe UI', 10),
            bg='#a4262c',
            fg='white',
            relief=tk.FLAT,
            bd=0,
            padx=15,
            pady=8,
            command=self.clean_all
        )
        clean_all_btn.pack(side=tk.LEFT, padx=5, pady=10)
        
        # COM口列表框架
        list_frame = tk.Frame(main_frame, bg=WIN11_COLORS['card_bg'],
                             relief=tk.FLAT, bd=1,
                             highlightbackground=WIN11_COLORS['border'],
                             highlightthickness=1)
        list_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 15))
        
        # 创建Treeview
        columns = ("端口", "设备名称", "描述", "制造商", "状态")
        self.tree = ttk.Treeview(list_frame, columns=columns, show="tree headings", 
                                height=15, selectmode='extended')
        
        # 设置列标题和宽度
        self.tree.heading("#0", text="☐")
        self.tree.column("#0", width=40, minwidth=40, stretch=False)
        
        column_widths = {
            "端口": 80,
            "设备名称": 200,
            "描述": 200,
            "制造商": 150,
            "状态": 80
        }
        
        for col in columns:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=column_widths.get(col, 100), 
                           minwidth=80)
        
        # 添加滚动条
        scrollbar_y = ttk.Scrollbar(list_frame, orient="vertical", 
                                   command=self.tree.yview)
        scrollbar_x = ttk.Scrollbar(list_frame, orient="horizontal", 
                                   command=self.tree.xview)
        self.tree.configure(yscrollcommand=scrollbar_y.set, 
                          xscrollcommand=scrollbar_x.set)
        
        # 布局
        self.tree.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        scrollbar_y.grid(row=0, column=1, sticky=(tk.N, tk.S))
        scrollbar_x.grid(row=1, column=0, sticky=(tk.W, tk.E))
        
        list_frame.columnconfigure(0, weight=1)
        list_frame.rowconfigure(0, weight=1)
        
        # 绑定双击事件切换选中状态
        self.tree.bind('<Double-Button-1>', self.toggle_selection)
        self.tree.bind('<space>', self.toggle_selection)
        
        # 信息面板
        info_frame = tk.Frame(main_frame, bg=WIN11_COLORS['card_bg'],
                             relief=tk.FLAT, bd=1,
                             highlightbackground=WIN11_COLORS['border'],
                             highlightthickness=1)
        info_frame.pack(fill=tk.X)
        
        self.info_var = tk.StringVar(value="就绪 | 共 0 个COM口")
        info_label = tk.Label(
            info_frame,
            textvariable=self.info_var,
            font=('Segoe UI', 9),
            bg=WIN11_COLORS['card_bg'],
            fg=WIN11_COLORS['text_secondary'],
            anchor=tk.W
        )
        info_label.pack(side=tk.LEFT, padx=15, pady=10)
        
        # 帮助信息
        help_label = tk.Label(
            info_frame,
            text="💡 提示：双击或按空格键切换选中状态 | 🟢绿色=已插入 🟠橙色=未插入",
            font=('Segoe UI', 9),
            bg=WIN11_COLORS['card_bg'],
            fg=WIN11_COLORS['text_secondary']
        )
        help_label.pack(side=tk.RIGHT, padx=15, pady=10)
        
        # 存储选中状态
        self.selected_items = set()
    
    def refresh_port_list(self):
        """刷新COM口列表"""
        # 清空现有项
        for item in self.tree.get_children():
            self.tree.delete(item)
        
        self.selected_items.clear()
        
        # 获取COM口列表
        ports = self.manager.get_com_ports()
        
        # 配置标签样式（用于区分已插入和未插入）
        self.tree.tag_configure('connected', background='#e8f5e9')  # 浅绿色 - 已插入
        self.tree.tag_configure('disconnected', background='#fff3e0')  # 浅橙色 - 未插入
        
        # 统计
        connected_count = 0
        disconnected_count = 0
        
        # 添加到树形视图
        for port in ports:
            is_connected = port.get("is_connected", False)
            if is_connected:
                connected_count += 1
                tag = 'connected'
            else:
                disconnected_count += 1
                tag = 'disconnected'
            
            item_id = self.tree.insert("", tk.END, text="☐", 
                tags=(tag,),
                values=(
                    port["port"],
                    port.get("friendly_name", "未知"),
                    port.get("description", "未知设备"),
                    port.get("manufacturer", "未知"),
                    port["status"]
                ))
        
        # 更新信息
        total = len(ports)
        self.info_var.set(
            f"就绪 | 共 {total} 个COM口 | "
            f"已插入: {connected_count} | 未插入: {disconnected_count}"
        )
    
    def toggle_selection(self, event=None):
        """切换选中状态"""
        selection = self.tree.selection()
        if not selection:
            return
        
        for item in selection:
            if item in self.selected_items:
                self.selected_items.remove(item)
                self.tree.item(item, text="☐")
            else:
                self.selected_items.add(item)
                self.tree.item(item, text="☑")
        
        self.update_info()
    
    def select_all(self):
        """全选"""
        self.selected_items.clear()
        for item in self.tree.get_children():
            self.selected_items.add(item)
            self.tree.item(item, text="☑")
        self.update_info()
    
    def deselect_all(self):
        """取消全选"""
        for item in self.selected_items:
            self.tree.item(item, text="☐")
        self.selected_items.clear()
        self.update_info()
    
    def update_info(self):
        """更新信息栏"""
        total = len(self.tree.get_children())
        selected = len(self.selected_items)
        
        # 统计已插入和未插入的数量
        connected_count = 0
        disconnected_count = 0
        for item in self.tree.get_children():
            tags = self.tree.item(item, 'tags')
            if 'connected' in tags:
                connected_count += 1
            elif 'disconnected' in tags:
                disconnected_count += 1
        
        self.info_var.set(
            f"就绪 | 共 {total} 个COM口 | "
            f"已插入: {connected_count} | 未插入: {disconnected_count} | "
            f"已选中: {selected} 个"
        )
    
    def clean_selected(self):
        """清理选中的COM口"""
        if not self.selected_items:
            messagebox.showwarning("警告", "请先选择要清理的COM口！")
            return
        
        # 检查管理员权限
        if not is_admin():
            messagebox.showwarning(
                "需要管理员权限",
                "清理COM口需要管理员权限。\n\n"
                "请以管理员身份运行此程序。"
            )
            # 询问是否以管理员身份重启
            if run_as_admin("清理COM口"):
                return
            else:
                return
        
        # 确认对话框
        result = messagebox.askyesno(
            "确认清理",
            f"确定要清理选中的 {len(self.selected_items)} 个COM口吗？\n\n"
            "此操作将从注册表中删除这些COM口的映射。\n\n"
            "是否继续？"
        )
        
        if not result:
            return
        
        # 执行清理
        deleted_count = 0
        failed_ports = []
        
        for item in self.selected_items:
            values = self.tree.item(item)["values"]
            port_name = values[0]
            
            if self.manager.delete_com_port(port_name):
                deleted_count += 1
            else:
                failed_ports.append(port_name)
        
        # 显示结果
        if deleted_count > 0:
            messagebox.showinfo(
                "清理完成",
                f"成功清理 {deleted_count} 个COM口！\n\n"
                f"失败: {len(failed_ports)} 个\n\n"
                "注意：某些COM口可能需要管理员权限才能清理。"
            )
        else:
            messagebox.showerror(
                "清理失败",
                "未能清理任何COM口。\n\n"
                "可能原因：\n"
                "1. 需要管理员权限\n"
                "2. COM口正在被使用\n"
                "3. 系统保护的COM口"
            )
        
        # 刷新列表
        self.refresh_port_list()
    
    def clean_all(self):
        """清理所有COM口"""
        ports = self.manager.get_com_ports()
        
        if not ports:
            messagebox.showinfo("提示", "当前没有可清理的COM口。")
            return
        
        # 检查管理员权限
        if not is_admin():
            messagebox.showwarning(
                "需要管理员权限",
                "清理COM口需要管理员权限。\n\n"
                "请以管理员身份运行此程序。"
            )
            # 询问是否以管理员身份重启
            if run_as_admin("清理COM口"):
                return
            else:
                return
        
        # 确认对话框
        result = messagebox.askyesno(
            "确认清理全部",
            f"确定要清理全部 {len(ports)} 个COM口吗？\n\n"
            "此操作将从注册表中删除所有COM口的映射。\n\n"
            "警告：这可能会影响正在使用的设备！\n\n"
            "是否继续？"
        )
        
        if not result:
            return
        
        # 执行清理
        deleted_count = self.manager.delete_all_com_ports()
        
        # 显示结果
        if deleted_count > 0:
            messagebox.showinfo(
                "清理完成",
                f"成功清理 {deleted_count} 个COM口！\n\n"
                f"失败: {len(ports) - deleted_count} 个\n\n"
                "注意：某些COM口可能需要管理员权限才能清理。"
            )
        else:
            messagebox.showerror(
                "清理失败",
                "未能清理任何COM口。\n\n"
                "可能原因：\n"
                "1. 需要管理员权限\n"
                "2. COM口正在被使用\n"
                "3. 系统保护的COM口"
            )
        
        # 刷新列表
        self.refresh_port_list()
    
    def on_closing(self):
        """窗口关闭时的处理"""
        self.root.quit()
        self.root.destroy()
    
    def run(self):
        """运行COM口清理工具"""
        self.root.mainloop()

    
class ScreenshotTool:
    """截图工具类"""
    
    def __init__(self, parent=None):
        if parent:
            self.root = tk.Toplevel(parent)
            self.root.transient(parent)
            self.root.grab_set()
        else:
            self.root = tk.Tk()
        self.setup_window()
        self.setup_ui()
        self.screenshot_count = 0
        
    def setup_window(self):
        """设置窗口"""
        self.root.title("截图工具")
        self.root.geometry("400x300")
        self.root.configure(bg=WIN11_COLORS['bg'])
        self.root.resizable(False, False)
        
        # 设置窗口置顶
        self.root.attributes('-topmost', True)
        
        # 设置窗口关闭协议
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        
    def setup_ui(self):
        """设置用户界面"""
        main_frame = tk.Frame(self.root, bg=WIN11_COLORS['bg'])
        main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
        
        # 标题
        title_label = tk.Label(
            main_frame,
            text="📸 截图工具",
            font=('Segoe UI', 18, 'bold'),
            bg=WIN11_COLORS['bg'],
            fg=WIN11_COLORS['text']
        )
        title_label.pack(pady=(0, 20))
        
        # 截图选项
        options_frame = tk.Frame(main_frame, bg=WIN11_COLORS['bg'])
        options_frame.pack(fill=tk.X, pady=(0, 20))
        
        # 全屏截图按钮
        fullscreen_btn = tk.Button(
            options_frame,
            text="🖥️ 全屏截图",
            font=('Segoe UI', 12),
            bg=WIN11_COLORS['accent'],
            fg='white',
            relief=tk.FLAT,
            bd=0,
            padx=20,
            pady=10,
            command=self.fullscreen_screenshot
        )
        fullscreen_btn.pack(fill=tk.X, pady=(0, 10))
        
        # 区域截图按钮
        region_btn = tk.Button(
            options_frame,
            text="✂️ 区域截图",
            font=('Segoe UI', 12),
            bg=WIN11_COLORS['accent'],
            fg='white',
            relief=tk.FLAT,
            bd=0,
            padx=20,
            pady=10,
            command=self.region_screenshot
        )
        region_btn.pack(fill=tk.X, pady=(0, 10))
        
        # 延时截图按钮
        delay_btn = tk.Button(
            options_frame,
            text="⏱️ 延时截图 (3秒)",
            font=('Segoe UI', 12),
            bg=WIN11_COLORS['accent'],
            fg='white',
            relief=tk.FLAT,
            bd=0,
            padx=20,
            pady=10,
            command=self.delay_screenshot
        )
        delay_btn.pack(fill=tk.X, pady=(0, 10))
        
        # 设置框架
        settings_frame = tk.LabelFrame(
            main_frame,
            text="设置",
            font=('Segoe UI', 10),
            bg=WIN11_COLORS['bg'],
            fg=WIN11_COLORS['text']
        )
        settings_frame.pack(fill=tk.X, pady=(0, 20))
        
        # 保存路径
        path_frame = tk.Frame(settings_frame, bg=WIN11_COLORS['bg'])
        path_frame.pack(fill=tk.X, padx=10, pady=5)
        
        tk.Label(
            path_frame,
            text="保存路径:",
            font=('Segoe UI', 9),
            bg=WIN11_COLORS['bg'],
            fg=WIN11_COLORS['text']
        ).pack(side=tk.LEFT)
        
        self.save_path = tk.StringVar(value=os.path.join(os.path.expanduser("~"), "Desktop"))
        path_entry = tk.Entry(
            path_frame,
            textvariable=self.save_path,
            font=('Segoe UI', 9),
            bg=WIN11_COLORS['card_bg'],
            fg=WIN11_COLORS['text'],
            relief=tk.FLAT,
            bd=1
        )
        path_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(10, 5))
        
        browse_btn = tk.Button(
            path_frame,
            text="浏览",
            font=('Segoe UI', 9),
            bg=WIN11_COLORS['border'],
            fg=WIN11_COLORS['text'],
            relief=tk.FLAT,
            bd=0,
            command=self.browse_save_path
        )
        browse_btn.pack(side=tk.RIGHT)
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_label = tk.Label(
            main_frame,
            textvariable=self.status_var,
            font=('Segoe UI', 9),
            bg=WIN11_COLORS['bg'],
            fg=WIN11_COLORS['text_secondary']
        )
        status_label.pack(side=tk.BOTTOM, anchor=tk.W)
        
    def fullscreen_screenshot(self):
        """全屏截图"""
        self.status_var.set("正在进行全屏截图...")
        self.root.withdraw()  # 隐藏窗口
        
        # 延时一点让窗口完全隐藏
        self.root.after(100, self._take_fullscreen_screenshot)
        
    def _take_fullscreen_screenshot(self):
        """执行全屏截图"""
        try:
            import tkinter as tk
            from tkinter import messagebox
            
            # 使用Windows系统截图工具
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"screenshot_{timestamp}.png"
            filepath = os.path.join(self.save_path.get(), filename)
            
            # 使用Windows截图命令
            result = subprocess.run([
                'powershell', '-Command',
                f'Add-Type -AssemblyName System.Windows.Forms; '
                f'$screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds; '
                f'$bitmap = New-Object System.Drawing.Bitmap $screen.Width, $screen.Height; '
                f'$graphics = [System.Drawing.Graphics]::FromImage($bitmap); '
                f'$graphics.CopyFromScreen(0, 0, 0, 0, $bitmap.Size); '
                f'$bitmap.Save("{filepath}", [System.Drawing.Imaging.ImageFormat]::Png); '
                f'$graphics.Dispose(); $bitmap.Dispose()'
            ], capture_output=True, text=True)
            
            if result.returncode == 0:
                self.status_var.set(f"截图已保存: {filename}")
                messagebox.showinfo("成功", f"截图已保存到:\n{filepath}")
            else:
                # 备用方案：使用系统截图工具
                subprocess.run(['snippingtool'], check=False)
                self.status_var.set("已启动系统截图工具")
                
        except Exception as e:
            messagebox.showerror("错误", f"截图失败: {str(e)}")
            self.status_var.set("截图失败")
        finally:
            self.root.deiconify()  # 显示窗口
            
    def region_screenshot(self):
        """区域截图"""
        self.status_var.set("启动区域截图...")
        try:
            # 使用Windows截图工具的区域截图功能
            subprocess.run(['snippingtool', '/clip'], check=False)
            self.status_var.set("已启动区域截图工具")
        except Exception as e:
            messagebox.showerror("错误", f"启动区域截图失败: {str(e)}")
            
    def delay_screenshot(self):
        """延时截图"""
        self.status_var.set("3秒后将进行截图...")
        self.root.withdraw()  # 隐藏窗口
        
        # 3秒倒计时
        for i in range(3, 0, -1):
            self.status_var.set(f"{i}秒后截图...")
            self.root.update()
            time.sleep(1)
            
        self._take_fullscreen_screenshot()
        
    def browse_save_path(self):
        """浏览保存路径"""
        folder = filedialog.askdirectory(
            title="选择截图保存路径",
            initialdir=self.save_path.get()
        )
        if folder:
            self.save_path.set(folder)
    
    def on_closing(self):
        """窗口关闭时的处理"""
        self.root.quit()
        self.root.destroy()
            
    def run(self):
        """运行截图工具"""
        self.root.mainloop()


def main():
    """主函数"""
    # 检查是否在Windows系统上运行
    if sys.platform != "win32":
        print("此程序只能在Windows系统上运行！")
        return
    
    try:
        # 启动 Win11 工具箱主界面
        app = Win11ToolboxGUI()
        app.run()
    except ImportError as e:
        messagebox.showerror("导入错误", f"导入模块失败：{str(e)}")
    except Exception as e:
        messagebox.showerror("错误", f"程序运行出错：{str(e)}")


if __name__ == "__main__":
    main()